
#include "Common/Errors.h"
#include "Common/Extras.h"

#undef GetEnvironmentVariable
#undef CreateWindow
#include "UtilManager.h"
#include "GuiThread.h"
#include "Parameters/ParameterManager.h"
#include "Pipelines/PipelineManager.h"
#include "CastingRoutines.h"

using namespace ttg::extras::serialization;
using namespace ttg::services;

extern "C"
{
	//Should be called before call of any other functions.
	__declspec(dllexport) void __stdcall init()
	{
		try
		{
			ttg_internal::utils::ParameterManager::init();
			ttg_internal::utils::PipelineManager::init();
		}
		catch (System::Exception ^ex)
		{ System::Console::WriteLine(ex->ToString()); }
	}
	//Shows tray icon. User will be able to load additional utilities.
	__declspec(dllexport) void __stdcall activateWindow()
	{
		try
		{ ttg_internal::utils::GuiThread::CreateWindow(); }
		catch (System::Exception ^ex)
		{ System::Console::WriteLine(ex->ToString()); }
	}
	//Should be called after the last call of dll-functions.
	__declspec(dllexport) void __stdcall close()
	{
		try
		{
			ttg_internal::utils::PipelineManager::close();
			ttg_internal::utils::ParameterManager::close();
		}
		catch (System::Exception ^ex)
		{ System::Console::WriteLine(ex->ToString()); }
	}
	__declspec(dllexport) void __stdcall initUtility(void *serialized_props,
													 size_t size_in_bytes)
	{
		//Deserializing.
		ByteDeSerializer deserializer(serialized_props, size_in_bytes);
		ttg::utils::UtilityProps utility;
		deserializer.deserializeObject(utility, "props");
		String ^err = ttg_internal::utils::UtilManager::Init(CastingRoutines::castUtilityProps(&utility));
		if (err != nullptr)
			switch (utility.onError)
			{
				case ttg::utils::UtilityProps::ShowMessage:
					System::Windows::Forms::MessageBox::Show(err, "Utility error");
					break;
				case ttg::utils::UtilityProps::ThrowError:
					throw ttg::Error(ttg::Error::FATAL, "UtilManager", "Init",
									 CastingRoutines::castString(err).c_str());
				case ttg::utils::UtilityProps::DoNothing:
				default:
					break;
			}
	}

	/*__declspec(dllexport) void __stdcall updateUtility_Pipeline(const char *name,
																ttg_internal::pipeline::PipelineInfo *pipeline)
	{
		//Not implemented yet.
	}*/

	__declspec(dllexport) void __stdcall updateUtility_Devices(void *serialized_devices,
															   size_t size_in_bytes)
	{
		try
		{
			//Deserializing.
			ByteDeSerializer deserializer(serialized_devices, size_in_bytes);
			int count;
			deserializer.deserializeInt(count, "count");
			DeviceInfo **devices = new DeviceInfo *[count];
			for (int i = 0; i < count; i++)
			{
				devices[i] = new DeviceInfo();
				deserializer.deserializeObject(devices[i], "device");
			}
			//Updating.
			ttg_internal::utils::GlobalInfo ^info;
			if ((info = ttg_internal::utils::UtilManager::GetInfo()) != nullptr)
			{
				CastingRoutines::updateGlobalInfo(info, devices, count);
			}
			//Deleting temporary objects.
			for (int i = 0; i < count; i++)
				SAFE_DELETE(devices[i]);
			SAFE_DELETE_ARRAY(devices);
		}
		catch (System::Exception ^ex)
		{
			System::Windows::Forms::MessageBox::Show(gcnew String("Internal error: ") + ex->ToString(), "Error");
		}
	}

	__declspec(dllexport) void __stdcall closeUtility(const char *name)
	{
		ttg_internal::utils::UtilManager::Close(gcnew String(name));
	}
}
